package SGEngine2

import (
	"fmt"
	"reflect"
)

type Node struct {
	Transfrom
	render     *Renderer
	Bounds     *Bounds
	Components map[string]IComponent

	childNodes *Array
	Parent     *Node
	active     bool
}

func ZeroNode() *Node {
	n := &Node{}
	n.Scale = VecOne
	m := Mat4Identity
	n.active = true
	n.LocalToWorld = &m

	return n
}

func (this *Node) SetActive(b bool) {
	if this.active == b {
		return
	}
	this.active = b
	this.setChilddActive(this, this.active)
}

func (this *Node) setChilddActive(node *Node, pactive bool) {
	if pactive == true {
		pactive = node.active
	}
	for _, v := range node.Components {
		if pactive {
			v.OnEnable(node)
		} else {
			v.OnDisable(node)
		}
	}

	if node.childNodes != nil {
		for i := 0; i < node.childNodes.Count(); i++ {
			this.setChilddActive(node.childNodes.Get(i).(*Node), pactive)
		}
	}

}

func (this *Node) ActiveSelf() bool {
	return this.active
}

func (this *Node) Active() bool {
	for this.Parent != nil && this.active != false {
		this = this.Parent
	}
	return this.active
}

func (this *Node) SetPosition(x, y, z float64) {
	this.Position.X = x
	this.Position.Y = y
	this.Position.Z = z
}

func (this *Node) GetWorldPosition() Vec3 {
	return this.GetWorldMat().Position()
}

func (n *Node) SetRender(render *Renderer) {
	n.render = render
}
func (n *Node) GetRender() *Renderer {
	return n.render
}

func (n *Node) Add(commpent IComponent) {
	if commpent == nil {
		fmt.Println("cant't add nil commpent")
	}

	if n.Components == nil {
		n.Components = make(map[string]IComponent)
	}
	n.Components[reflect.TypeOf(commpent).Elem().Name()] = commpent
	commpent.OnAttach(n)
	if n.Active() {
		commpent.OnEnable(n)
	}
}

func (n *Node) Get(typeName string) IComponent {
	return n.Components[typeName]
}

func (n *Node) GetChild() *Array {
	return n.childNodes
}
func (n *Node) AddChild(node *Node) {
	if n.childNodes == nil {
		n.childNodes = new(Array)
	}
	node.Parent = n
	n.childNodes.Add(node)
}

func (n *Node) RemoveChild(node *Node) {
	for _, v := range n.Components {
		v.OnDetach(node)
	}
	if n.childNodes != nil {
		n.childNodes.Remove(node)
	}
}

func (n *Node) AddChildComponent(node *Node, cs ...IComponent) *Node {

	for _, v := range cs {
		node.Add(v)
	}

	n.AddChild(node)
	return node
}

func (n *Node) Update() {
	for _, v := range n.Components {
		v.OnUpdate()
	}
}

func (n *Node) IfGet(fn func(k string, v interface{}) bool) interface{} {
	for k, v := range n.Components {
		if fn(k, v) {
			return v
		}
	}
	return nil
}
